import asyncio
import uuid
from datetime import datetime
from typing import Dict, Optional
from concurrent.futures import ThreadPoolExecutor
import threading
from pathlib import Path

from src.models.base import TaskStatus, CourseContent, ProcessStep, TaskProgress
from src.utils.ai_course_parser import AICourseParser
from src.utils.logger import get_logger

logger = get_logger(__name__)


class TaskManager:
    """异步任务管理器."""
    
    def __init__(self):
        self.tasks: Dict[str, TaskStatus] = {}
        self.executor = ThreadPoolExecutor(max_workers=4)
        self.parser = AICourseParser()
        self._lock = threading.RLock()
    
    def create_task_from_content(self, content: str) -> str:
        """从文本内容创建解析任务."""
        return self._create_task(content=content)
    
    def create_task_from_file(self, file_path: str, file_type: str, original_filename: str = None) -> str:
        """从文件创建解析任务."""
        file_info = {
            "file_path": file_path,
            "file_type": file_type,
            "original_filename": original_filename or Path(file_path).name,
            "file_size": Path(file_path).stat().st_size if Path(file_path).exists() else 0
        }
        return self._create_task(file_path=file_path, file_type=file_type, file_info=file_info)
    
    def _create_task(self, content: str = None, file_path: str = None, file_type: str = None, file_info: dict = None) -> str:
        """创建任务的内部方法."""
        task_id = str(uuid.uuid4())
        
        # 初始化所有处理步骤
        steps = [
            ProcessStep(step_name="content_analysis", status="pending", message="等待内容分析"),
            ProcessStep(step_name="course_introduction", status="pending", message="等待课程介绍生成"),
            ProcessStep(step_name="course_requirements", status="pending", message="等待课程须知生成"),
            ProcessStep(step_name="chapter_generation", status="pending", message="等待章节生成"),
            ProcessStep(step_name="points_generation", status="pending", message="等待要点生成"),
            ProcessStep(step_name="knowledge_graph", status="pending", message="等待知识图谱生成"),
            ProcessStep(step_name="learning_paths", status="pending", message="等待学习路径生成"),
            ProcessStep(step_name="result_assembly", status="pending", message="等待结果组装")
        ]
        
        progress = TaskProgress(
            total_steps=len(steps),
            current_step=0,
            overall_progress=0,
            current_step_name="准备开始",
            current_step_message="任务已创建，等待处理",
            steps=steps
        )
        
        task_status = TaskStatus(
            task_id=task_id,
            status="pending",
            file_info=file_info,
            progress=progress
        )
        
        with self._lock:
            self.tasks[task_id] = task_status
        
        # 异步执行任务
        if content:
            asyncio.create_task(self._process_content_task(task_id, content))
        elif file_path and file_type:
            asyncio.create_task(self._process_file_task(task_id, file_path, file_type))
        
        logger.info(f"创建任务: {task_id}")
        return task_id
    
    def get_task_status(self, task_id: str) -> Optional[TaskStatus]:
        """获取任务状态."""
        with self._lock:
            return self.tasks.get(task_id)
    
    def _update_step_progress(self, task_id: str, step_name: str, status: str, progress: int, message: str, details: dict = None):
        """更新步骤进度的回调函数."""
        with self._lock:
            if task_id not in self.tasks:
                return
                
            task = self.tasks[task_id]
            task.updated_at = datetime.now()
            
            # 查找并更新对应步骤
            step_index = None
            for i, step in enumerate(task.progress.steps):
                if step.step_name == step_name:
                    step_index = i
                    step.status = status
                    step.progress = progress
                    step.message = message
                    if details:
                        step.details = details
                    
                    if status == "processing" and not step.start_time:
                        step.start_time = datetime.now()
                    elif status in ["completed", "failed"] and not step.end_time:
                        step.end_time = datetime.now()
                    break
            
            if step_index is not None:
                # 更新任务整体进度
                task.progress.current_step = step_index + 1
                task.progress.current_step_name = step_name
                task.progress.current_step_message = message
                
                # 计算总体进度
                completed_steps = sum(1 for step in task.progress.steps if step.status == "completed")
                task.progress.overall_progress = int((completed_steps / len(task.progress.steps)) * 100)
                
                # 如果当前步骤失败，标记整个任务失败
                if status == "failed":
                    task.status = "failed"
                    task.error_message = message
                elif status == "completed" and step_index == len(task.progress.steps) - 1:
                    # 最后一步完成，任务完成
                    task.status = "completed"
                elif status == "processing":
                    task.status = "processing"
            
            logger.info(f"任务进度更新: {task_id} - {step_name} - {status} ({progress}%)")
    
    def update_task_result(self, task_id: str, result: CourseContent):
        """更新任务结果."""
        with self._lock:
            if task_id in self.tasks:
                self.tasks[task_id].result = result
                logger.info(f"任务结果已更新: {task_id}")
    
    async def _process_content_task(self, task_id: str, content: str):
        """处理文本内容解析任务."""
        try:
            # 设置进度回调
            def progress_callback(step_name, status, progress, message, details=None):
                self._update_step_progress(task_id, step_name, status, progress, message, details)
            
            self.parser.set_progress_callback(progress_callback)
            
            # 执行解析
            result = await self.parser.parse_from_content(content)
            
            # 更新结果
            self.update_task_result(task_id, result)
            
        except Exception as e:
            error_message = f"内容解析失败: {str(e)}"
            logger.error(f"任务 {task_id} 失败: {str(e)}")
            # 标记当前步骤失败
            with self._lock:
                if task_id in self.tasks:
                    task = self.tasks[task_id]
                    current_step_name = task.progress.current_step_name or "content_analysis"
                    self._update_step_progress(task_id, current_step_name, "failed", 0, error_message)
    
    async def _process_file_task(self, task_id: str, file_path: str, file_type: str):
        """处理文件解析任务."""
        try:
            # 设置进度回调
            def progress_callback(step_name, status, progress, message, details=None):
                self._update_step_progress(task_id, step_name, status, progress, message, details)
            
            self.parser.set_progress_callback(progress_callback)
            
            # 执行解析
            result = await self.parser.parse_from_file(file_path, file_type)
            
            # 更新结果
            self.update_task_result(task_id, result)
            
        except Exception as e:
            error_message = f"文件解析失败: {str(e)}"
            logger.error(f"任务 {task_id} 失败: {str(e)}")
            # 标记当前步骤失败
            with self._lock:
                if task_id in self.tasks:
                    task = self.tasks[task_id]
                    current_step_name = task.progress.current_step_name or "file_parsing"
                    self._update_step_progress(task_id, current_step_name, "failed", 0, error_message)
    
    def cleanup_old_tasks(self, hours: int = 24):
        """清理超过指定小时数的旧任务."""
        cutoff_time = datetime.now().timestamp() - (hours * 3600)
        
        with self._lock:
            tasks_to_remove = []
            for task_id, task in self.tasks.items():
                if task.created_at.timestamp() < cutoff_time:
                    tasks_to_remove.append(task_id)
            
            for task_id in tasks_to_remove:
                del self.tasks[task_id]
                logger.info(f"清理旧任务: {task_id}")


# 全局任务管理器实例
task_manager = TaskManager()